#include "Poker.h"

Poker::Poker()
{
 // Init all attributes
 initPokerCombinations();
 initPokerArray();

 // To define the cards weight
 initCardsPositionArray();
}

void Poker::initCardsPositionArray()
{
 cardsPosition.insert('2', 1);
 cardsPosition.insert('3', 2);
 cardsPosition.insert('4', 3);
 cardsPosition.insert('5', 4);
 cardsPosition.insert('6', 5);
 cardsPosition.insert('7', 6);
 cardsPosition.insert('8', 7);
 cardsPosition.insert('9', 8);
 cardsPosition.insert('T', 9);
 cardsPosition.insert('J', 10);
 cardsPosition.insert('Q', 11);
 cardsPosition.insert('K', 12);
 cardsPosition.insert('A', 13);
}

void Poker::initPokerCombinations()
{
 setPairOnBoard(false);
 setTwoPairsOnBoard(false);
 setThreeOfAKindOnBoard(false);
 setFullHouseOnBoard(false);
 setFourOfAKindOnBoard(false);

 setPair(false);
 setTwoPairs(false);
 setThreeOfAKind(false);
 setFullHouse(false);
 setFourOfAKind(false);

 setKickerWeighting(0);
}

void Poker:: initPokerArray()
{
 boardCardsNumberArrayIndexedByCard.clear();
 globalCardsNumberArrayIndexedByCard.clear();
 cardsArraySortedByCardWeight.clear();
 cardsPositionArrayIndexedByCard.clear();
}

/**
 * Getter
 */
bool Poker::getPairOnBoard()
{
 return pairOnBoard;
}

bool Poker::getTwoPairsOnBoard()
{
 return twoPairsOnBoard;
}

bool Poker::getThreeOfAKindOnBoard()
{
 return threeOfAKindOnBoard;
}

bool Poker::getFullHouseOnBoard()
{
 return fullHouseOnBoard;
}

bool Poker::getFourOfAKindOnBoard()
{
 return fourOfAKindOnBoard;
}

bool Poker::getPair()
{
 return pair;
}

bool Poker::getTwoPairs()
{
 return twoPairs;
}

bool Poker::getThreeOfAKind()
{
 return threeOfAKind;
}

bool Poker::getFullHouse()
{
 return fullHouse;
}

bool Poker::getFourOfAKind()
{
 return fourOfAKind;
}

int Poker::getKickerWeighting()
{
 return kickerWeighting;
}

int Poker::getCombinationWeighting1()
{
 return combinationWeighting1;
}

int Poker::getCombinationWeighting2()
{
 return combinationWeighting2;
}

/**
 * Setter
 */
void Poker::setPairOnBoard(bool _pairOnBoard)
{
 pairOnBoard = _pairOnBoard;
}

void Poker::setTwoPairsOnBoard(bool _twoPairsOnBoard)
{
 twoPairsOnBoard = _twoPairsOnBoard;
}

void Poker::setThreeOfAKindOnBoard(bool _threeOfAKindOnBoard)
{
 threeOfAKindOnBoard = _threeOfAKindOnBoard;
}

void Poker::setFullHouseOnBoard(bool _fullHouseOnBoard)
{
 fullHouseOnBoard = _fullHouseOnBoard;
}

void Poker::setFourOfAKindOnBoard(bool _fourOfAKindOnBoard)
{
 fourOfAKindOnBoard = _fourOfAKindOnBoard;
}

void Poker::setPair(bool _pair)
{
 pair = _pair;
}

void Poker::setTwoPairs(bool _twoPairs)
{
 twoPairs = _twoPairs;
}

void Poker::setThreeOfAKind(bool _threeOfAKind)
{
 threeOfAKind = _threeOfAKind;
}

void Poker::setFullHouse(bool _fullHouse)
{
 fullHouse = _fullHouse;
}

void Poker::setFourOfAKind(bool _fourOfAKind)
{
 fourOfAKind = _fourOfAKind;
}

void Poker::setKickerWeighting(int _kickerWeighting)
{
 kickerWeighting = _kickerWeighting;
}

void Poker::setCombinationWeighting1(int _combinationWeighting1)
{
 combinationWeighting1 = _combinationWeighting1;
}

void Poker::setCombinationWeighting2(int _combinationWeighting2)
{
 combinationWeighting2 = _combinationWeighting2;
}

int Poker::Combination(GameInfo & gameInfo, int numPlayer)
{
 initPokerCombinations();
 initPokerArray();

 qDebug() << "Build a board cards number array indexed by card...";
 BuildBoardCardsNumberArrayIndexedByCard(gameInfo);

 qDebug() << "Build a global (board + player) cards number array indexed by card...";
 BuildGlobalCardsNumberArrayIndexedByCard(gameInfo, numPlayer);

 qDebug() << "Build an array sorted by card weight...";
 BuildArraySortedByCardWeight(gameInfo, numPlayer);

 qDebug() << "Build a card position array indexed by card...";
 BuildCardsPositionArrayIndexedByCard();

 qDebug() << "Search the combination on board...";
 CombinationOnBoard();
 DisplayCombinationOnBoard();

 qDebug() << "Search the player combination...";
 FindPlayerCombination(gameInfo, numPlayer);
 DisplayPlayerCombination();

 if(fourOfAKind)
 {
  gameInfo.getPlayer(numPlayer).setCombinationLabel("Four of a kind");
  return 5;
 }
 else if(fullHouse)
 {
  gameInfo.getPlayer(numPlayer).setCombinationLabel("Full house");
  return 4;
 }
 else if(threeOfAKind)
 {
  gameInfo.getPlayer(numPlayer).setCombinationLabel("Three of a kind");
  return 3;
 }
 else if(twoPairs)
 {
  gameInfo.getPlayer(numPlayer).setCombinationLabel("Two pairs");
  return 2;
 }
 else if(pair)
 {
  gameInfo.getPlayer(numPlayer).setCombinationLabel("Pair");
  return 1;
 }

 return 0;
}

void Poker::BuildBoardCardsNumberArrayIndexedByCard(GameInfo & gameInfo)
{
 QMapIterator<int,Card> boardCardsNumberArrayIndexedByCardIterator(gameInfo.getBoardCards());

 while(boardCardsNumberArrayIndexedByCardIterator.hasNext())
 {
	 boardCardsNumberArrayIndexedByCardIterator.next();

  QChar cardName = boardCardsNumberArrayIndexedByCardIterator.value().getCardName();

  if(boardCardsNumberArrayIndexedByCard.contains(cardName))
   boardCardsNumberArrayIndexedByCard[cardName]++;
  else
   boardCardsNumberArrayIndexedByCard.insert(cardName,1);
 }
}

void Poker::BuildGlobalCardsNumberArrayIndexedByCard(GameInfo & gameInfo, int numPlayer)
{
 globalCardsNumberArrayIndexedByCard = boardCardsNumberArrayIndexedByCard;

 // Ugly part
 for(int i=0; i<2; i++)
 {
  QChar cardName = gameInfo.getPlayer(numPlayer).getCard(i).getCardName();

  if(globalCardsNumberArrayIndexedByCard.contains(cardName))
   globalCardsNumberArrayIndexedByCard[cardName]++;
  else
   globalCardsNumberArrayIndexedByCard.insert(cardName, 1);
 }
}

void Poker::BuildArraySortedByCardWeight(GameInfo & gameInfo, int numPlayer)
{
 int cardPosition;

 QMapIterator<QChar,int> boardCardsNumberArrayIndexedByCardIterator(boardCardsNumberArrayIndexedByCard);

 while(boardCardsNumberArrayIndexedByCardIterator.hasNext())
 {
  boardCardsNumberArrayIndexedByCardIterator.next();

  cardPosition = cardsPosition.value(boardCardsNumberArrayIndexedByCardIterator.key());

  if(!cardsArraySortedByCardWeight.contains(cardPosition))
   cardsArraySortedByCardWeight.insert(cardPosition, boardCardsNumberArrayIndexedByCardIterator.key());
 }

 // Ugly part
 for(int i=0; i<2; i++)
 {
  QChar cardName = gameInfo.getPlayer(numPlayer).getCard(i).getCardName();

  cardPosition = cardsPosition.value(cardName);

  if(!cardsArraySortedByCardWeight.contains(cardPosition))
   cardsArraySortedByCardWeight.insert(cardPosition, cardName);
 }

 QMapIterator<QChar,int> globalCardsNumberArrayIndexedByCardIterator(globalCardsNumberArrayIndexedByCard);

 while(globalCardsNumberArrayIndexedByCardIterator.hasNext())
 {
  globalCardsNumberArrayIndexedByCardIterator.next();

  qDebug() << globalCardsNumberArrayIndexedByCardIterator.key() << " : " << globalCardsNumberArrayIndexedByCardIterator.value();
 }
}

void Poker::BuildCardsPositionArrayIndexedByCard()
{
 int position = 1;

 QMapIterator<int,QChar> cardsArraySortedByCardWeightIterator(cardsArraySortedByCardWeight);

 while(cardsArraySortedByCardWeightIterator.hasNext())
 {
  cardsArraySortedByCardWeightIterator.next();

  cardsPositionArrayIndexedByCard.insert(cardsArraySortedByCardWeightIterator.value(), position);

  position++;
 }
}

void Poker::CombinationOnBoard()
{
 QMapIterator<QChar,int> boardCardsNumberArrayIndexedByCardIterator(boardCardsNumberArrayIndexedByCard);

 while(boardCardsNumberArrayIndexedByCardIterator.hasNext())
 {
  boardCardsNumberArrayIndexedByCardIterator.next();

  qDebug() << boardCardsNumberArrayIndexedByCardIterator.key() << " : " << boardCardsNumberArrayIndexedByCardIterator.value();

  switch(boardCardsNumberArrayIndexedByCardIterator.value())
  {
   case 2: if(!getPairOnBoard())
	        setPairOnBoard(true);
		   else
		   {
			setPairOnBoard(false);
            setTwoPairsOnBoard(true);
		   }
		   break;
   case 3: setThreeOfAKindOnBoard(true);
		   break;
   case 4: setFourOfAKindOnBoard(true);
		   break;
  }
 }

 if(getPairOnBoard() && getThreeOfAKindOnBoard())
 {
  setPairOnBoard(false);
  setThreeOfAKindOnBoard(false);
  setFullHouseOnBoard(true);
 }
}

void Poker::DisplayCombinationOnBoard()
{
 if(getPairOnBoard())
  qDebug() << "Pair on board";

 if(getTwoPairsOnBoard())
  qDebug() << "Two pairs on board";

 if(getThreeOfAKindOnBoard())
  qDebug() << "Three of a kind on board";

 if(getFullHouseOnBoard())
  qDebug() << "Full house on board";

 if(getFourOfAKindOnBoard())
  qDebug() << "Square on board";
}

void Poker::FindPlayerCombination(GameInfo & gameInfo, int numPlayer)
{
 QChar Card1 = gameInfo.getPlayer(numPlayer).getCard(0).getCardName();
 QChar Card2 = gameInfo.getPlayer(numPlayer).getCard(1).getCardName();

 // If pair in hand
 if(Card1 == Card2)
 {
  QMapIterator<QChar,int> boardCardsNumberArrayIndexedByCardIterator(boardCardsNumberArrayIndexedByCard);

  while(boardCardsNumberArrayIndexedByCardIterator.hasNext())
  {
   boardCardsNumberArrayIndexedByCardIterator.next();

   if(boardCardsNumberArrayIndexedByCardIterator.key() == Card1)
   {
	// Four of a kind
    if(boardCardsNumberArrayIndexedByCardIterator.value() == 2)
    {
     setFourOfAKind(true);
     // No weighting ??

     return;
    }
    else
    {
     if(getPairOnBoard())
     {
      setFullHouse(true);

      // Full house weighting
      setKickerWeighting(cardsPositionArrayIndexedByCard[Card1]);

      return;
     }
     // Three of a kind
	 else
	 {
	  setThreeOfAKind(true);
	  // TODO: Three of a kind weighting

	  return;
	 }
    }
   }
  }

  // Full house
  if(getThreeOfAKindOnBoard())
  {
   setFullHouse(true);
   // TODO: weighting

   return;
  }

  // Two pairs
  if(getPairOnBoard())
  {
   setTwoPairs(true);
   // TODO: weighting

   return;
  }

  setPair(true);
  // TODO: weighting
 }
 else
 {
  QMapIterator<QChar,int> globalCardsNumberArrayIndexedByCardIterator(globalCardsNumberArrayIndexedByCard);

  while(globalCardsNumberArrayIndexedByCardIterator.hasNext())
  {
   globalCardsNumberArrayIndexedByCardIterator.next();

   switch(globalCardsNumberArrayIndexedByCardIterator.value())
   {
    case 2: if(!getPair())
	 		 setPair(true);
		    else
		    {
			 setPair(false);
			 setTwoPairs(true);
		    }
		    break;

    case 3: if(!getPair())
    	     setThreeOfAKind(true);
			else
             setFullHouse(true);
		    break;
    case 4: setFourOfAKindOnBoard(true);
		    break;
   }
  }
 }
}

void Poker::DisplayPlayerCombination()
{
 QString msg = "Player combination: ";

 if(getPair())
  qDebug() << msg << "pair";

 if(getTwoPairs())
  qDebug() << msg << "two pairs";

 if(getThreeOfAKind())
  qDebug() << msg << "three of a kind";

 if(getFullHouse())
  qDebug() << msg << "full house";

 if(getFourOfAKind())
  qDebug() << msg << "four of a kind";

 if(getKickerWeighting() != 0)
  qDebug() << "Kicker weighting : " << kickerWeighting;
}

int Poker::getWinner(GameInfo & gameInfo)
{
	 if(Combination(gameInfo, 1) < Combination(gameInfo, 2))
		 return 1;
	 else
		 return 2;
/*
	if(Combination(gameInfo, 1) < Combination(gameInfo, 2))
  return 2;
 else
  return 1;
*/
 return 0;
}
